home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / eagle.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  24KB  |  805 lines

  1. /*
  2.  * Interface driver for the EAGLE board for KA9Q's TCP/IP on an IBM-PC ONLY!
  3.  *
  4.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  5.  *  Permission for non-commercial use is hereby granted provided this notice
  6.  *  is retained.  For info call: (301) 997-3838.
  7.  *
  8.  *  10 Jan 88    ng6q    - Corrected IDLE comparison in doegstat.
  9.  *   6 Apr 88    ng6q    - Changed eg_raw to prevent calling egtxint with a
  10.  *              packet in sndbuf.  Initialized sndq and rcvq in
  11.  *              eg_attach.  Added carrier detect check before
  12.  *              slot time delay in egtxint.  Should make major
  13.  *              changes to egtxint to avoid delay loops while
  14.  *              masked for receive interrupts.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include "global.h"
  19. #include "mbuf.h"
  20. #include "iface.h"
  21. #include "eagle.h"
  22. #include "8530.h"
  23. #include "ax25.h"
  24. #include "trace.h"
  25. #include <time.h>
  26.  
  27. struct EGTAB eagle[EGMAX];    /* Device table - one entry per card */
  28. void eg0vec(),write_scc(),rts(),waitmsec();
  29. void (*eghandle[])() = { eg0vec };  /* handler interrupt vector table */
  30. struct egchan egchan[2*EGMAX];       /* channel table - 2 entries per card */
  31. int16 egnbr;
  32.  
  33. /* Master interrupt handler.  One interrupt at a time is handled.
  34.  * here. Service routines are called from here.
  35.  */
  36. void
  37. egint(dev)
  38. int16 dev;
  39. {
  40.     register char st;
  41.     register int16 pcbase;
  42.     struct egchan *hp;
  43.     void egrxint(),egtxint(),egexint();
  44.  
  45.     eagle[dev].ints++;
  46.     pcbase = eagle[dev].addr;
  47.  
  48.     /* Read interrupt status register from channel A */
  49.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0) {
  50.         /* Use IFs to process ALL interrupts pending
  51.          * because we need to check all interrupt conditions
  52.          */
  53.         if (st & CHARxIP) {
  54.             /* Channel A Rcv Interrupt Pending */
  55.             hp = &egchan[2 * dev];
  56.             egrxint(hp);
  57.         } else if (st & CHATxIP) {
  58.             /* Channel A Transmit Int Pending */
  59.             hp = &egchan[2 * dev];
  60.             egtxint(hp);
  61.         } else if (st & CHAEXT) {
  62.             /* Channel A External Status Int */
  63.             hp = &egchan[2 * dev];
  64.             egexint(hp);
  65.         } else if (st & CHBRxIP) {
  66.             /* Channel B Rcv Interrupt Pending */
  67.             hp = &egchan[(2 * dev)+1];
  68.             egrxint(hp);
  69.         } else if (st & CHBTxIP) {
  70.             /* Channel B Transmit Int Pending */
  71.             hp = &egchan[(2 * dev)+1];
  72.             egtxint(hp);
  73.         } else if (st & CHBEXT) {
  74.             /* Channel B External Status Int */
  75.             hp = &egchan[(2 * dev)+1];
  76.             egexint(hp);
  77.         }
  78.         /* Reset highest interrupt under service */
  79.         write_scc(hp->base+CTL,R0,RES_H_IUS);
  80.     } /* End of while loop on int processing */
  81. }
  82.  
  83. /* Eagle SIO External/Status interrupts
  84.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  85.  * Receiver automatically goes to Hunt on an abort.
  86.  *
  87.  * If the Tx Underrun interrupt hits, change state and
  88.  * issue a reset command for it, and return.
  89.  */
  90. static void
  91. egexint(hp)
  92. register struct egchan *hp;
  93. {
  94.     char st, i_state;
  95.  
  96.     i_state = disable();        /* disable interrupts */
  97.     hp->exints++;
  98.     st = read_scc(hp->base+CTL,R0);     /* Fetch status */
  99.  
  100.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  101.     if((hp->rstate==0) && (st & TxEOM)) {
  102.         /* if in UNDERRUN, go to FLAGOUT state
  103.          * see explanation under egtxint()
  104.          * CRC & FLAG now going out, so
  105.          * wait for Tx BUffer Empty int
  106.          */
  107.  
  108.         /* If we are not in underrun, this is an unexpected
  109.          * underrun.  EOM bit should be set, so the SCC will
  110.          * now send an abort
  111.          */
  112.  
  113.         if(hp->tstate == UNDERRUN)
  114.             hp->tstate = FLAGOUT;
  115.  
  116.         /* Tx Buff EMPTY interrupt occurs after CRC is sent */
  117.     }
  118.  
  119.     /* Receive Mode only
  120.      * This triggers when hunt mode is entered, & since an ABORT
  121.      * automatically enters hunt mode, we use that to clean up
  122.      * any waiting garbage
  123.      */
  124.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)) {
  125.         hp->rcp = hp->rcvbuf->data;
  126.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  127.         hp->aborts++;              /* nbr aborts * 2 */
  128.     }
  129.  
  130.     /* reset external status latch */
  131.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  132.  
  133.     restore(i_state);
  134. }
  135.  
  136. /* EG receive interrupt handler. The first receive buffer is pre-allocated
  137.  * in the init routine.  Thereafter, it is filled here, queued out, and a
  138.  * new one acquired.  CRC, OVERRUN and TOOBIG errors merely 'rewind' the
  139.  * pointers and reuse the same buffer.
  140.  */
  141. static void
  142. egrxint(hp)
  143. register struct egchan *hp;
  144. {
  145.     register int16 base;
  146.     char rse, i_state;
  147.  
  148.     i_state = disable();        /* disable interrupts */
  149.     hp->rxints++;
  150.     base = hp->base;
  151.  
  152.     if ((read_scc(base+CTL,R0)) & Rx_CH_AV) {
  153.         /* there is a char to be stored
  154.          * read special condition bits before reading the data char
  155.          */
  156.         rse = read_scc(hp->base+CTL,R1); /* get status byte from R1 */
  157.         if(rse & Rx_OVR) {
  158.             /* Rx overrun - toss buffer */
  159.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  160.             hp->rcvbuf->cnt = 0;
  161.             hp->rstate = RXERROR;    /* set error flag */
  162.             hp->rovers++;        /* count overruns */
  163.         } else if(hp->rcvbuf->cnt >= hp->bufsiz) {
  164.             /* Too large -- toss buffer */
  165.             hp->toobig++;
  166.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  167.             hp->rcvbuf->cnt = 0;
  168.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  169.         }
  170.         /* ok, we can store the received character now */
  171.         if(hp->rstate == ACTIVE) {        /* If no errors... */
  172.             *hp->rcp++ = inportb(base+DATA);    /* char to rcv buff */
  173.             hp->rcvbuf->cnt++;            /* bump count */
  174.         } else {
  175.             /* got to empty FIFO */
  176.             (void) inportb(base+DATA);
  177.             write_scc(hp->base+CTL,R0,ERR_RES);    /* reset err latch */
  178.             hp->rstate = ACTIVE;
  179.         }
  180.     }
  181.     /* char has been stored
  182.      * read special condition bits
  183.      */
  184.     rse = read_scc(hp->base+CTL,R1);     /* get status byte from R1 */
  185.  
  186.     /* The End of Frame bit is ALWAYS associated with a character,
  187.      * usually, it is the last CRC char.  Only when EOF is true can
  188.      * we look at the CRC byte to see if we have a valid frame
  189.      */
  190.     if(rse & END_FR) {
  191.         hp->rxframes++;
  192.         /* END OF FRAME -- Make sure Rx was active */
  193.         if(hp->rcvbuf->cnt > 0) {        /* any data to store */
  194.             /* looks like a frame was received
  195.              * now is the only time we can check for CRC error
  196.              */
  197.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) || (hp->rcvbuf->cnt < 10)) {
  198.                 /* error occurred; toss frame */
  199.                 if(rse & CRC_ERR)
  200.                     hp->crcerr++;    /* count CRC errs */
  201.                 if(hp->rstate == RXERROR)
  202.                     hp->rovers++;
  203.                 /* don't throw away buffer -
  204.                  * merely reset the pointers
  205.                  */
  206.                 hp->rcp = hp->rcvbuf->data;
  207.                 hp->rcvbuf->cnt = 0;
  208.             } else {
  209.                 /* Here we have a valid frame */
  210.                 hp->rcvbuf->cnt -= 2;           /* Toss 2 crc bytes */
  211.                 enqueue(&hp->rcvq,hp->rcvbuf);       /* queue it in */
  212.                 hp->enqueued++;
  213.  
  214.                 /* packet queued - get buffer for next frame */
  215.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  216.                 hp->rcp = hp->rcvbuf->data;
  217.                 hp->rcvbuf->cnt = 0;
  218.                 if(hp->rcvbuf == NULLBUF) {
  219.                     /* No memory, abort receiver */
  220.                     restore(i_state);
  221.                     printf("DISASTER! Out of Memory for Receive!\n");
  222.                     fflush(stdout);
  223.                     write_scc(CTL+base,R3,Rx8);
  224.                     return;
  225.                 }
  226.             } /* end good frame queued */
  227.         }  /* end check for active receive upon EOF */
  228.         hp->rstate = ACTIVE;    /* and clear error status */
  229.     } /* end EOF check */
  230.     restore(i_state);
  231. }
  232.  
  233. /* egchan transmit interrupt service routine
  234.  *
  235.  * The state variable tstate, along with some static pointers,
  236.  * represents the state of the transmit "process".
  237.  */
  238. static void
  239. egtxint(hp)
  240. register struct egchan *hp;
  241. {
  242.     register int16 base;
  243.     char i_state,c;
  244.  
  245.     i_state = disable();
  246.  
  247.     if(hp->tstate != DEFER && hp->tstate) hp->txints++;
  248.     base = hp->base;
  249.  
  250.     switch(hp->tstate) {
  251.     case FLAGOUT:
  252.         /* Here after CRC sent and Tx interrupt fires.
  253.          * To give the SCC a chance to get the FLAG
  254.          * out, we delay 100 Ms
  255.          */
  256.         hp->tstate = IDLE;    /* fall thru to IDLE */
  257.         waitmsec(10);        /* 100 msec wait for flag Tx */
  258.         /* Note, it may be possible to stuff out a
  259.          * meaningless character, wait for the interrupt
  260.          * then go to idle.  A delay is absolutely necessary
  261.          * here else the packet gets truncated prematurely
  262.          * when no other packet is waiting to be sent.
  263.          * IDLE state indicates either we are starting a brand new packet
  264.          * as a result of its being queued for transmission (egtxint called
  265.          * from eg_raw), or after a frame has been transmitted (as a
  266.          * result of a Tx buffer empty interrupt after the CRC/FLAG
  267.          */
  268.     case IDLE:
  269.         /* Transmitter idle. Find a frame for transmission */
  270.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF) {
  271.             /* Nothing to send - return to receive mode
  272.              * Tx OFF now - flag should have gone
  273.              */
  274.             rts(hp,OFF);
  275.             restore(i_state);
  276.             return;
  277.         }
  278.         /* If a buffer to send, we drop thru here */
  279.     case DEFER:        /* we may have deferred prev xmit attempt */
  280.         /* PPERSIST CALCULATION: we use the lower byte of the
  281.          * 8253 timer 0 count, as a random number (0-255).
  282.          * If the persist value is higher, wait one slot time
  283.          */
  284.         if(hp->params[PERSIST] >= peekb(0x6c,0x40))
  285.             waitmsec(hp->params[SLOTIME]);
  286.  
  287.         /* Check DCD so we don't step on a frame being received */
  288.         /* DCD is ACTIVE LOW on the SCC DCD pin, but the bit in R0 */
  289.         /* is SET when DCD is ACTIVE!! */
  290.  
  291.         if((read_scc(base+CTL,R0) & DCD) > 0) { /* Carrier Detected? */
  292.             hp->tstate = DEFER;    /* defer xmit */
  293.             /* don't release dequeued buffer...*/
  294.             restore(i_state);
  295.             return;
  296.         }
  297.  
  298.         rts(hp,ON);   /* Transmitter on */
  299.         /* ints not enabled yet */
  300.  
  301.         /* Get next char to send */
  302.         pullup(&hp->sndbuf,&c,1);        /* one char at a time */
  303.         write_scc(CTL+base,R0,RES_Tx_CRC);    /* reset for next frame */
  304.         outportb(base+DATA,c);        /* First char out now */
  305.  
  306.         /* select transmit interrupts to enable */
  307.  
  308.         write_scc(CTL+base,R15,TxUIE);        /* allow Underrun int only */
  309.         write_scc(CTL+base,R1,TxINT_ENAB|EXT_INT_ENAB);  /* Tx/Extern ints on */
  310.         write_scc(CTL+base,R9,MIE|NV);        /* master enable */
  311.         /* enable interrupt latch on board */
  312.         outportb(hp->dmactrl,INTENABLE);
  313.  
  314.         hp->tstate = ACTIVE;    /* char going out now */
  315.         restore(i_state);
  316.         return;
  317.  
  318.     case ACTIVE:
  319.         /* Here we are actively sending a frame */
  320.         if(pullup(&hp->sndbuf,&c,1) == 1) {
  321.             outportb(hp->base+DATA,c);    /* next char is gone */
  322.             /* stuffing a char satisfies Interrupt condition */
  323.         } else {
  324.             /* No more to send - just stop till underrun int */
  325.             hp->tstate = UNDERRUN;
  326.             free_p(hp->sndbuf);
  327.             /* now we reset the EOM latch & enable underrun int */
  328.             write_scc(CTL+base,R0,RES_EOM_L);    /* send CRC at underrun */
  329.             write_scc(CTL+hp->base,R0,RES_Tx_P); /* reset Tx Int Pend */
  330.         }
  331.         restore(i_state);
  332.         return;     /* back to wait for interrupt */
  333.  
  334.     case UNDERRUN:
  335.         /*
  336.          * This state is handled by an UNDERRUN interrupt, which
  337.          * is an External Status interrupt.  At UNDERRUN, the
  338.          * UNDERRUN/EOM latch in R0 will be 0, so the SCC will send
  339.          * CRC and ending flag.  After the CRC clears the Tx buffer,
  340.          * a TX BUFF EMPTY interrupt will fire.  At that time, we
  341.          * should be in FLAGOUT state, ready to send another frame
  342.          * if one is there to send.
  343.          */
  344.         break;
  345.     } /* end switch */
  346.     restore(i_state);
  347. }
  348.  
  349. /* SET Transmit or Receive Mode
  350.  * Set RTS (request-to-send) to modem on Transmit
  351.  */
  352. static void
  353. rts(hp,x)
  354. register struct egchan *hp;
  355. int16 x;
  356. {
  357. int16 tc;
  358. long br;
  359.  
  360.     /* Reprogram BRG and turn on transmitter to send flags */
  361.     if(x == ON) {                /* Turn Tx ON and Receive OFF */
  362.         write_scc(CTL+hp->base,R3,Rx8);    /* Rx off */
  363.         waitmsec(50);            /* 500 msec delay before on */
  364.         hp->rstate = IDLE;
  365.         write_scc(CTL+hp->base,R9,0);    /* Interrupts off */
  366.         br = hp->speed;         /* get desired speed */
  367.         tc = (XTAL/br)-2;        /* calc 1X BRG divisor */
  368.         write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  369.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  370.  
  371.         write_scc(CTL+hp->base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
  372.         /* Transmitter now on */
  373.         write_scc(CTL+hp->base,R0,RES_Tx_CRC);/* CRC reset */
  374.         waitmsec(hp->params[TXDELAY]);      /* Delay after Tx on */
  375.     } else {    /* Tx OFF and Rx ON */
  376.         hp->tstate = IDLE;
  377.         write_scc(CTL+hp->base,R5,Tx8|DTR);     /* TX off now */
  378.         write_scc(CTL+hp->base,R0,ERR_RES);     /* reset error bits */
  379.  
  380.         write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  381.         write_scc(CTL+hp->base,R15,BRKIE);        /* allow ABORT int */
  382.  
  383.         /* delay for squelch tail before enable of Rx */
  384.         waitmsec(hp->params[SQUELDELAY]);    /* keep it up  */
  385.  
  386.         /* Reprogram BRG for 32x clock for receive DPLL */
  387.         write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  388.         br = hp->speed;             /* get desired speed */
  389.         tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  390.         write_scc(CTL+hp->base,R12,tc&0xFF);    /* lower byte */
  391.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF);    /* upper bite */
  392.         write_scc(CTL+hp->base,R14,BRSRC|SEARCH);    /* SEARCH mode, keep BRG source */
  393.         write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  394.  
  395.         /* Now, turn on the receiver and hunt for a flag */
  396.         write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  397.         hp->rstate = ACTIVE;            /* Normal state */
  398.     }
  399. }
  400.  
  401. /* Initialize eg controller parameters */
  402. static int
  403. egchanparam(hp)
  404. register struct egchan *hp;
  405. {
  406.     int16 tc;
  407.     long br;
  408.     char i_state;
  409.     register int16 base;
  410.  
  411.     /* Initialize 8530 channel for SDLC operation */
  412.  
  413.     base = hp->base;
  414. #ifdef    notdef
  415.     printf("Initializing Channel %c - Base = %x\n",base&2?'A':'B',base);
  416. #endif
  417.     i_state = disable();
  418.  
  419.     switch(base & 2){
  420.     case 2:
  421.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  422.         break;
  423.     case 0:
  424.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  425.         break;
  426.     }
  427.  
  428.     /* Deselect all Rx and Tx interrupts */
  429.     write_scc(CTL+base,R1,0);
  430.  
  431.     /* Turn off external interrupts (like CTS/CD) */
  432.     write_scc(CTL+base,R15,0);
  433.  
  434.     /* X1 clock, SDLC mode */
  435.     write_scc(CTL+base,R4,SDLC|X1CLK);           /* SDLC mode and X1 clock */
  436.  
  437.     /* Now some misc Tx/Rx parameters */
  438.     /* CRC PRESET 1, NRZI Mode */
  439.     write_scc(CTL+base,R10,CRCPS|NRZI);
  440.  
  441.     /* Set up BRG and DPLL multiplexers */
  442.     /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
  443.     write_scc(CTL+base,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
  444.  
  445.     /* Null out SDLC start address */
  446.     write_scc(CTL+base,R6,0);
  447.  
  448.     /* SDLC flag */
  449.     write_scc(CTL+base,R7,FLAG);
  450.  
  451.     /* Set up the Transmitter but don't enable it */
  452.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  453.     write_scc(CTL+base,R5,Tx8|DTR);
  454.  
  455.     /* Receiver - intial setup only - more later */
  456.     write_scc(CTL+base,R3,Rx8);            /* 8 bits/char */
  457.  
  458.     /* Setting up BRG now - turn it off first */
  459.     write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  460.  
  461.     /* set the 32x time constant for the BRG in Receive mode */
  462.  
  463.     br = hp->speed;             /* get desired speed */
  464.     tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  465.  
  466.     write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  467.     write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  468.  
  469.     /* Time to set up clock control register for RECEIVE mode
  470.      * Eagle has xtal osc going to pclk at 3.6864 Mhz
  471.      * The BRG is sourced from that, and set to 32x clock
  472.      * The DPLL is sourced from the BRG, and feeds the TRxC pin
  473.      * Transmit clock & Receive clock come from DPLL
  474.      */
  475.  
  476.     /* Following subroutine sets up and ENABLES the receiver */
  477.     rts(hp,OFF);           /* TX OFF and RX ON */
  478.  
  479.     write_scc(CTL+hp->base,R14,BRSRC|SSBR);       /* DPLL from BRG, BRG source is PCLK */
  480.     write_scc(CTL+hp->base,R14,BRSRC|SEARCH);       /* SEARCH mode, keep BRG source */
  481.  
  482.     write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  483.  
  484.     /* enable the receive interrupts */
  485.  
  486.     write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  487.     write_scc(CTL+hp->base,R15,BRKIE);        /* ABORT int */
  488.     write_scc(CTL+hp->base,R9,MIE|NV);    /* master enable */
  489.  
  490.     /* enable interrupt latch on board */
  491.     outportb(hp->dmactrl,INTENABLE);
  492.  
  493.     /* Now, turn on the receiver and hunt for a flag */
  494.     write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  495.  
  496.     restore(i_state);
  497.     return 0;
  498. }
  499.  
  500. /* Attach a EAGLE interface to the system
  501.  * argv[0]: hardware type, must be "eagle"
  502.  * argv[1]: I/O address, e.g., "0x300"
  503.  * argv[2]: vector, e.g., "2"
  504.  * argv[3]: mode, must be:
  505.  *        "ax25" (AX.25 UI frame format)
  506.  * argv[4]: interface label, e.g., "eg0"
  507.  * argv[5]: receiver packet buffer size in bytes
  508.  * argv[6]: maximum transmission unit, bytes
  509.  * argv[7]: interface speed, e.g, "1200"
  510.  */
  511. int
  512. eg_attach(argc,argv)
  513. int argc;
  514. char *argv[];
  515. {
  516.     register struct interface *if_pca,*if_pcb;
  517.     extern struct interface *ifaces;
  518.     struct egchan *hp;
  519.     int dev;
  520.     int eg_init();
  521.     void doeg();
  522.     int eg_stop();
  523.     int ax_send();
  524.     int ax_output();
  525.     int eg_raw();
  526.     int eg_ctl();
  527.     void (*getirq())();
  528.  
  529.     /* Quick check to make sure args are good and mycall is set */
  530.     if(strcmp(argv[3],"ax25") != 0){
  531.         printf("Mode %s unknown for interface %s\r\n",
  532.             argv[3],argv[4]);
  533.         return -1;
  534.     }
  535.     axarp();
  536.     if(mycall.call[0] == '\0'){
  537.         printf("set mycall first\r\n");
  538.         return -1;
  539.     }
  540.     /* Note: More than one card can be supported if you give up a COM:
  541.      * port, thus freeing up an IRQ line and port address
  542.      */
  543.  
  544.     if(egnbr >= EGMAX) {
  545.         printf("Only 1 EAGLE controller supported right now!\r\n");
  546.         return -1;
  547.     }
  548.     dev = egnbr++;
  549.  
  550.     /* Initialize hardware-level control structure */
  551.     eagle[dev].addr = htoi(argv[1]);
  552.     eagle[dev].vec = htoi(argv[2]);
  553.  
  554.     /* Save original interrupt vector */
  555.     eagle[dev].oldvec = getirq(eagle[dev].vec);
  556.  
  557.     /* Set new interrupt vector */
  558.     if(setirq(eagle[dev].vec,eghandle[dev]) == -1){
  559.         printf("IRQ %u out of range\n",eagle[dev].vec);
  560.         egnbr--;
  561.         return -1;
  562.     }
  563.     /* Create interface structures and fill in details */
  564.     if_pca = (struct interface *)calloc(1,sizeof(struct interface));
  565.     if_pcb = (struct interface *)calloc(1,sizeof(struct interface));
  566.  
  567.     /* Append "a" to interface associated with A channel */
  568.     if_pca->name = malloc((unsigned)strlen(argv[4])+2);
  569.     strcpy(if_pca->name,argv[4]);
  570.     strcat(if_pca->name,"a");
  571.     /* Append "b" to interface associated with B channel */
  572.     if_pcb->name = malloc((unsigned)strlen(argv[4])+2);
  573.     strcpy(if_pcb->name,argv[4]);
  574.     strcat(if_pcb->name,"b");
  575.  
  576.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  577.     if_pcb->ioctl = if_pca->ioctl = eg_ctl;
  578.     if_pca->dev = 2*dev;            /* eg0a */
  579.     if_pcb->dev = 2*dev + 1;        /* eg0b */
  580.     if_pcb->recv = if_pca->recv = doeg;
  581.     if_pcb->stop = if_pca->stop = eg_stop;
  582.     if_pcb->output = if_pca->output = ax_output;
  583.     if_pcb->raw = if_pca->raw = eg_raw;
  584.  
  585.     if(strcmp(argv[3],"ax25") == 0) {
  586.         /* Must be true, was checked at top */
  587.         if_pcb->send = if_pca->send = ax_send;
  588.         if(if_pcb->hwaddr == NULLCHAR)
  589.             if_pcb->hwaddr = malloc(sizeof(mycall));
  590.         memcpy(if_pcb->hwaddr,(char *)&mycall,sizeof(mycall));
  591.         if(if_pca->hwaddr == NULLCHAR)
  592.             if_pca->hwaddr = malloc(sizeof(mycall));
  593.         memcpy(if_pca->hwaddr,(char *)&mycall,sizeof(mycall));
  594.     }
  595.     /* Link em in to the interface chain */
  596.     if_pca->next = if_pcb;
  597.     if_pcb->next = ifaces;
  598.     ifaces = if_pca;
  599.  
  600.     /* set params in egchan table for CHANNEL B */
  601.  
  602.     hp = &egchan[2*dev+1];                /* eg1 is offset 1 */
  603.     hp->stata = eagle[dev].addr + CHANA + CTL;    /* permanent status */
  604.     hp->statb = eagle[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  605.     hp->dmactrl = eagle[dev].addr + DMACTRL;    /* Eagle control reg */
  606.     hp->speed = (int16)atoi(argv[7]);
  607.     hp->base = eagle[dev].addr + CHANB;
  608.     hp->bufsiz = atoi(argv[5]);
  609.     hp->tstate = IDLE;
  610.     /* default KISS Params */
  611.     hp->params[TXDELAY] = 25;        /* 250 Ms */
  612.     hp->params[PERSIST] = 64;        /* 25% persistence */
  613.     hp->params[SLOTIME] = 10;        /* 100 Ms */
  614.     hp->params[SQUELDELAY] = 20;        /* 200 Ms */
  615.  
  616.     write_scc(CTL+hp->stata,R9,FHWRES);     /* Hardware reset */
  617.                         /* one time only */
  618.     /* Disable interrupts with Master interrupt ctrl reg */
  619.     write_scc(CTL+hp->stata,R9,0);
  620.  
  621.     egchanparam(hp);
  622.  
  623.     /* Pre-allocate a receive buffer */
  624.     hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  625.     if(hp->rcvbuf == NULLBUF) {
  626.         /* No memory, abort receiver */
  627.         printf("EGATTACH: No memory available for Receive buffers\n");
  628.         /* Restore original interrupt vector */
  629.         setirq(eagle[dev].vec,eagle[dev].oldvec);
  630.         egnbr--;
  631.         return(-1);
  632.     }
  633.     hp->rcp = hp->rcvbuf->data;
  634.     hp->rcvbuf->cnt = 0;
  635.     hp->sndq = NULLBUF;
  636.     hp->rcvq = NULLBUF;
  637.  
  638.     /* set params in egchan table for CHANNEL A */
  639.     hp = &egchan[2*dev];            /* eg0a is offset 0 */
  640.     hp->speed = (int16)atoi(argv[7]);
  641.     hp->base = eagle[dev].addr + CHANA;
  642.     hp->bufsiz = atoi(argv[5]);
  643.     hp->tstate = IDLE;
  644.     /* default KISS Params */
  645.     hp->params[TXDELAY] = 25;        /* 250 Ms */
  646.     hp->params[PERSIST] = 64;        /* 25% persistence */
  647.     hp->params[SLOTIME] = 10;        /* 100 Ms */
  648.     hp->params[SQUELDELAY] = 20;        /* 200 Ms */
  649.  
  650.     egchanparam(hp);
  651.  
  652.     /* Pre-allocate a receive buffer */
  653.     hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  654.     if(hp->rcvbuf == NULLBUF) {
  655.         /* No memory, abort receiver */
  656.         printf("EGATTACH: No memory available for Receive buffers\n");
  657.         /* Restore original interrupt vector */
  658.         setirq(eagle[dev].vec,eagle[dev].oldvec);
  659.         egnbr--;
  660.         return -1;
  661.     }
  662.     hp->rcp = hp->rcvbuf->data;
  663.     hp->rcvbuf->cnt = 0;
  664.     hp->sndq = NULLBUF;
  665.     hp->rcvq = NULLBUF;
  666.  
  667.     write_scc(CTL+hp->base,R9,MIE|NV);        /* master interrupt enable */
  668.  
  669.     /* Enable interrupts on the EAGLE card itself */
  670.     outportb(hp->dmactrl,INTENABLE);
  671.  
  672.     /* Enable interrupt */
  673.     maskon(eagle[dev].vec);
  674.  
  675.     return 0;
  676. }
  677.  
  678. /* Process incoming packets */
  679. void
  680. doeg(interface)
  681. struct interface *interface;
  682. {
  683.     struct egchan *hp;
  684.     struct mbuf *bp;
  685.  
  686.     hp = &egchan[interface->dev];
  687.     while((bp = dequeue(&hp->rcvq)) != NULLBUF){
  688.         hp->rcvcnt--;
  689.         dump(interface,IF_TRACE_IN,TRACE_AX25,bp);
  690.         ax_recv(interface,bp);
  691.     }
  692.     /*  Test for DEFERRED transmit state */
  693.     if (hp->tstate == DEFER)
  694.         egtxint(hp);
  695. }
  696.  
  697. /* Shut down interface */
  698. int
  699. eg_stop(iface)
  700. struct interface *iface;
  701. {
  702.     int16 dev;
  703.  
  704.     dev = iface->dev;
  705.     if(dev & 1)
  706.         return 0;
  707.     dev >>= 1;    /* Convert back into eagle number */
  708.  
  709.     /* Turn off interrupts */
  710.     maskoff(eagle[dev].vec);
  711.  
  712.     /* Restore original interrupt vector */
  713.     setirq(eagle[dev].vec,eagle[dev].oldvec);
  714.  
  715.     /* Force hardware reset */
  716.     write_scc(CTL+eagle[dev].addr + CHANA,R9,FHWRES);
  717.  
  718.     /* resets interrupt enable on eagle card itself */
  719.     outportb(eagle[dev].addr+DMACTRL,0);
  720.     return 0;
  721. }
  722.  
  723. /* Send raw packet on eagle card */
  724. int
  725. eg_raw(interface,bp)
  726. struct interface *interface;
  727. struct mbuf *bp;
  728. {
  729.     char kickflag;
  730.     struct egchan *hp;
  731.  
  732.     dump(interface,IF_TRACE_OUT,TRACE_AX25,bp);
  733.     hp = &egchan[interface->dev];
  734.     kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);    /* clever! flag=1 if something in queue */
  735.     enqueue(&hp->sndq,bp);
  736.     if(kickflag)            /* simulate interrupt to xmit */
  737.         egtxint(hp);        /* process interrupt */
  738.     return 0;
  739. }
  740. /* routine to delay n increments of 10 milliseconds
  741.  * about right on a turbo XT - will be slow on 4.77
  742.  * Still looking for a way to use the 8253 timer...
  743.  */
  744. void
  745. waitmsec(n)
  746. int n;
  747. {
  748.     long i;
  749.  
  750.     for(i=0L; i < (200L*n); i++)
  751.         ;  /* simple loop delay */
  752. }
  753.  
  754. /* display EAGLE Channel stats */
  755. int
  756. doegstat()
  757. {
  758.     struct egchan *hp0, *hp1;
  759.     int i;
  760.  
  761.     for(i=0; i<EGMAX; i++) {
  762.         hp0 = &egchan[i];
  763.         hp1 = &egchan[i+1];
  764.  
  765.         printf("EAGLE Board Statistics:\n\n");
  766.         printf("Base Addr\tRxints\tTxints\tExints\tEnqued\tCrcerr\tAborts\tRxOvers\tRFrames\n");
  767.         printf("---------\t------\t------\t------\t------\t------\t------\t-------\t-------\n");
  768.         printf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n", hp0->base, hp0->rxints,
  769.             hp0->txints, hp0->exints, hp0->enqueued, hp0->crcerr, hp0->aborts,
  770.             hp0->rovers,hp0->rxframes,
  771.             hp0->rstate==0?"IDLE":hp0->rstate==1?"ACTIVE":hp0->rstate==2?"RXERROR":hp0->rstate==3?"RXABORT":"TOOBIG");
  772.  
  773.         printf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n\n", hp1->base, hp1->rxints,
  774.             hp1->txints, hp1->exints, hp1->enqueued, hp1->crcerr, hp1->aborts,
  775.             hp1->rovers,hp1->rxframes,
  776.             hp1->rstate==0?"IDLE":hp1->rstate==1?"ACTIVE":hp1->rstate==2?"RXERROR":hp1->rstate==3?"RXABORT":"TOOBIG");
  777.     }
  778.     return 0;
  779. }
  780.  
  781. /* Subroutine to set kiss params in channel tables */
  782. int
  783. eg_ctl(interface,argc,argv)
  784. struct interface *interface;
  785. int argc;
  786. char *argv[];
  787. {
  788.     struct egchan *hp;
  789.     int p, v;
  790.  
  791.     if(argc < 2){
  792.         printf("Insufficient parameters\r\n");
  793.         return 1;
  794.     }
  795.     hp = &egchan[interface->dev];        /* point to channel table */
  796.     p = atoi(argv[0]);          /* parameter in binary */
  797.     if(p > 3){
  798.         printf("parameter %d out of range\r\n",p);
  799.         return 1;
  800.     }
  801.     v = atoi(argv[1]);          /* value to be loaded */
  802.     hp->params[p] = v;          /* Stuff in Kiss array */
  803.     return 0;
  804. }
  805.